package xerror

import (
	"bytes"
	"github.com/golang/protobuf/jsonpb"
	spb "google.golang.org/genproto/googleapis/rpc/status"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
)

// NewStatus 创建 status
func NewStatus(c codes.Code, msg string) *status.Status {
	return status.New(c, msg)
}

// NewStatusFromPalfishErrorInfo 创建以 PalfishErrorInfo 为错误详情的 status
// 注意: 如果 code 为 OK，将直接 panic！ (因为，如果一切 OK，则不应为之附带错误详情)
func NewStatusFromPalfishErrorInfo(c codes.Code, msg string, pei *PalfishErrorInfo) *status.Status {
	if c == codes.OK {
		panic("no error details for status with code OK")
	}
	s, _ := status.New(c, msg).WithDetails(pei)
	return s
}

// JSONMarshalStatus 将 status 序列化为 JSON 格式。
// 序列化后的结果形如:
// {"code":52,"message":"rate limited","details":[{"@type":"type.googleapis.com/xerror.PalfishErrorInfo","domain":"base/metadatacenter","biz_code":1192,"metadata":{"foo":"bar"}}]}
// 值得注意的是，details 数组中的元素包含额外的 @type 字段。
// 其值，前半部分 type.googleapis.com 是固定的，而后半部分 xerror.PalfishErrorInfo 指明了 pb message 对应的 package 与名称。
func JSONMarshalStatus(s *status.Status) ([]byte, error) {
	buf := new(bytes.Buffer)
	m := jsonpb.Marshaler{}
	err := m.Marshal(buf, s.Proto())
	if err != nil {
		return nil, err
	}
	return buf.Bytes(), nil
}

// JSONUnmarshalStatus 将 JSON 数据反序列化为 status。
// 注意，s 为 nil 时将 panic。
func JSONUnmarshalStatus(data []byte, s *status.Status) error {
	pbStatus := &spb.Status{}
	um := jsonpb.Unmarshaler{}
	err := um.Unmarshal(bytes.NewReader(data), pbStatus)
	if err != nil {
		return err
	}

	*s = *status.FromProto(pbStatus)
	return nil
}
